﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace CalcSharp.Core.Containers
{
    [Serializable]
    public class FloatSet : ASet
    {
        private List<float> Storage;

        public FloatSet()
        {
            Storage = new List<float>();
        }

        public FloatSet(int cnt)
        {
            this.Storage = new List<float>();
            for (int i=0; i<cnt; i++) this.Storage.Add(float.NaN);
        }

        public FloatSet(List<float> Existing)
        {
            if (Existing == null) throw new ArgumentNullException("Existing");
            this.Storage = Existing;
        }

        protected override void ValueAt(int index, double value)
        {
            float v;
            if (value > float.MaxValue) v = float.MaxValue;
            else if (value < float.MinValue) v = float.MinValue;
            else if (value == double.PositiveInfinity) v = float.PositiveInfinity;
            else if (value == double.NegativeInfinity) v = float.NegativeInfinity;
            else if (value == double.NaN) v = float.NaN;
            else v = (float)value;
            if (index >= 0 && index < Storage.Count) Storage[index] = v;
            else throw new IndexOutOfRangeException();
        }

        protected override double ValueAt(int index)
        {
            if (index >= 0 && index < Storage.Count) return Storage[index];
            else throw new IndexOutOfRangeException();
        }

        public override double[] ToArray()
        {
            double[] ret = new double[this.Count];
            for (int i = 0; i < ret.Length; i++)
            {
                ret[i] = Storage[i];
            }
            return ret;
        }

        public override int Count
        {
            get { return this.Storage.Count; }
        }

        public override bool Contains(double value)
        {
            return this.Storage.Contains((float)value);
        }

        public override void AddItem(double itm)
        {
            this.Storage.Add((float)itm);
        }

        public override void DeleteItem(int index)
        {
            this.Storage.RemoveAt(index);
        }

        public override ASet CreateSet(int Count)
        {
            return new FloatSet(Count);
        }

        public override ASet Randomize()
        {
            Random rgen = new Random();
            List<float> res = this.Storage;
            float tmp;
            int r1, r2;
            for (int i = 0; i < (this.Storage.Count / 2); i++)
            {
                r1 = rgen.Next(0, this.Storage.Count);
                r2 = rgen.Next(0, this.Storage.Count);
                tmp = this.Storage[r1];
                this.Storage[r1] = this.Storage[r2];
                this.Storage[r2] = tmp;
            }
            return new FloatSet(res);
        }

        public override ASet Unique()
        {
            Dictionary<float, int> dic = new Dictionary<float, int>();
            List<float> res = new List<float>();
            for (int i = 0; i < Storage.Count; i++)
            {
                if (dic.ContainsKey(Storage[i])) dic[Storage[i]]++;
                else dic.Add(Storage[i], 1);
            }
            foreach (float key in dic.Keys)
            {
                if ((dic[key] >= 1) && (!res.Contains(key))) res.Add(key);
            }
            return new FloatSet(res);
        }

        public override ASet Sort()
        {
            List<float> cpy = Storage;
            cpy.Sort();
            return new FloatSet(cpy);
        }

        public override ASet Reverse()
        {
            List<float> cpy = this.Storage;
            cpy.Reverse();
            return new FloatSet(cpy);
        }

        public static FloatSet operator +(FloatSet A, FloatSet B)
        {
            FloatSet result = new FloatSet(A.Count + B.Count);
            int i, last;
            for (i = 0; i < A.Count; i++) result[i] = A[i];
            last = A.Count;
            for (i = 0; i < B.Count; i++) result[last + i] = B[i];
            return result;
        } //A unio B

        public static FloatSet operator /(FloatSet A, FloatSet B)
        {
            List<float> temp = new List<float>();
            for (int i = 0; i < A.Count; i++)
            {
                if (!B.Contains(A[i])) temp.Add((float)A[i]);
            }
            return new FloatSet(temp);
        } // A külömbség B

        public static FloatSet operator *(FloatSet A, FloatSet B)
        {
            FloatSet tmp;
            List<float> its = new List<float>();
            if (A.Count > B.Count) tmp = B;
            else tmp = A;
            for (int i = 0; i < tmp.Count; i++)
            {
                if (A.Contains(tmp[i]) && B.Contains(tmp[i])) its.Add((float)tmp[i]);
            }
            return new FloatSet(its);
        } // A metszet B

        public static FloatSet operator %(FloatSet A, FloatSet B) //A szimetrikus különbség B
        {
            return (A / B) * (B / A);
        }
    }
}

